package com.lzh.gulimall.search.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName ThreadTest
 * @Description TODO
 * @Author liuzhihui
 * @Date 2020/8/29 15:30
 * @Version 1.0
 **/
public class ThreadTest {
    public static ExecutorService executorService= Executors.newFixedThreadPool(5);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main方法...start...");

        /**
         * 1.创建异步对象
         * CompletableFuture提供了四个静态方法来创建一个异步操作
         * runAsync异步执行任务，无返回值，可以使用默认的线程池执行，也可以指定线程池
         * public static CompletableFuture<Void> runAsync(Runnable runnable)
         * public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)
         * supplyAsync异步执行任务，有返回值，可以使用默认的线程池执行，也可以指定线程池
         * public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
         * public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)
         */

        //runAsync方式，无返回值
//        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getName());
//            int i = 10 / 2;
//            System.out.println("runAsync运行结果：" + i);
//        }, executorService);

        //supplyAsync方式，可获取返回值
//        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getName());
//            int i = 10 / 1;
//            return i;
//        }, executorService);
        //获取返回值
//        Integer integer = integerCompletableFuture.get();
//        System.out.println("supplyAsync运行结果：" + integer);

        /**
         *2.计算完成时回调方法
         *方法完成后的感知
         * whenComplete当任务之行成功之后，可以指定回调什么，用的线程和之前的一个
         * public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action)
         *
         * whenCompleteAsync当任务之行成功之后，可以指定回调什么，但是以异步的方式去执行，使用另一个线程
         * public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)
         * public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
         *
         * exceptionally的详细处理,whenComplete虽然也能处理异常，但是没法修改返回数据，exceptionally可以感知异常并返回默认值
         * public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
         */
//        integerCompletableFuture = integerCompletableFuture.whenComplete((result, exception) -> {
//            System.out.println("异步任务成功完成了...结果是：" + result);
//            System.out.println("异步任务成功完成了...异常是：" + exception);
//
//        }).exceptionally(throwable -> {
//            //感知异常并返回默认值
//            return 10;
//        });
//        Integer integer = integerCompletableFuture.get();
//        System.out.println("supplyAsync运行结果：" + integer);


        /**
         * 3.handle方法
         * 方法完成后的处理
         * 和whenComplete一样，可以对结果做最后的处理，可处理异常，可改变返回值
         * whenComplete能感知上一步是成功了，还是出现异常了，但是不能修改返回值
         * 能通过exceptionally来修改返回结果，也能使用handler方法来修改
         * public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
         * public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
         * public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor);
         *
         *
         */
//        integerCompletableFuture=integerCompletableFuture.handle((result,exception)->{
//            if (result!=null){
//                return result*2;
//            }
//            if (exception!=null){
//                return 0;
//            }
//            return null;
//        });
//        Integer integer = integerCompletableFuture.get();
//        System.out.println("supplyAsync运行结果：" + integer);

        /**
         * 4.线程串行化方法
         *
         * 上一个异步任务执行完，就执行thenApply的任务，接受上一步的返回值，thenApply的任务执行完有返回值
         * 加了Async，表示不使用上一个异步任务的线程，另外使用一个
         * public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
         * public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
         * public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
         *
         * 上一个异步任务执行完，，就执行thenAccept的任务，接受上一步的返回值，thenAccept的任务执行完无返回值
         * public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
         * public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
         * public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor)
         *
         * 上一个异步任务执行完，就执行thenRun的任务，不接受上一步的返回值，thenRun的任务执行完也无返回值
         * public CompletableFuture<Void> thenRun(Runnable action)
         * public CompletableFuture<Void> thenRunAsync(Runnable action)
         * public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)
         *
         */

        //thenRun:开启下一个任务，不能获取到上一步的执行结果，无返回值
        //任务1
//        CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getName());
//            int i = 10 / 1;
//            return i;
//        }, executorService)
//        //任务2
//         .thenRunAsync(()->{
//            System.out.println("任务2启动了");
//        },executorService);

        //thenAccept：开启下一个任务，能获取到上一步的执行结果，无返回值
        //任务1
//        CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getName());
//            int i = 10 / 1;
//            return i;
//        }, executorService)
//        //任务2
//        .thenAcceptAsync(result->{
//            System.out.println("任务2启动了");
//            System.out.println("任务1的执行结果："+result);
//        },executorService);

        //thenApply：开启下一个任务，能获取到上一步的执行结果，有返回值
        //任务1
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getName());
//            int i = 10 / 1;
//            return i;
//        }, executorService)
//        //任务2
//        .thenApplyAsync(result -> {
//            System.out.println("任务2启动了");
//            System.out.println("任务1的执行结果：" + result);
//            return result + 10;
//        }, executorService);
//        /**
//         * get方法会阻塞，比如上面的任务执行了5s,就会在get方法这里阻塞，直到任务执行完成，能获取到结果为止
//         */
//        Integer integer = future.get();
//        System.out.println("任务2的返回值为："+integer);

        /**
         * 5.两任务组合 - 都要完成
         *
         * thenCombine：组合两个future,获取两个future的返回结果，并返回当前任务的返回值
         * public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
         * public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
         * public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn, Executor executor)
         *
         * thenAcceptBoth:组合两个future,获取两个future任务的返回结果，然后处理任务，没有返回值
         * public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)
         * public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)
         * public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor)
         *
         *
         * runAfterBoth:组合两个future,不需要获取future的结果，只需要两个future处理完任务后，处理该任务
         * public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action)
         * public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action)
         * public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor)
         *
         */

        /**
         * 两个任务都完成，才执行任务3
         */
        //任务1
//        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1线程:" + Thread.currentThread().getName());
//            int i = 10 / 1;
//            System.out.println("任务1结束...");
//            return i;
//        }, executorService);
        //任务2
//        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务2线程:" + Thread.currentThread().getName());
//            int i = 10 / 10;
//            try {
//                Thread.sleep(3000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println("任务2结束...");
//            return i;
//        }, executorService);

        //两个任务都完成，才执行任务3,不需要之前任务的结果
//        future1.runAfterBothAsync(future2,()->{
//            System.out.println("任务3开始...");
//        },executorService);

        //两个任务都完成，才执行任务3,需要之前任务的结果
        //f1任务1的执行结果，f2任务2的执行结果
//        future1.thenAcceptBothAsync(future2,(f1,f2)->{
//            System.out.println("任务3开始...");
//            System.out.println("任务1执行结果:"+f1);
//            System.out.println("任务2执行结果:"+f2);
//        },executorService);

        //两个任务都完成，才执行任务3,需要之前任务的结果
        //f1任务1的执行结果，f2任务2的执行结果
        //有返回值
//        CompletableFuture<Integer> future = future1.thenCombineAsync(future2, (f1, f2) -> {
//            System.out.println("任务3开始...");
//            System.out.println("任务1执行结果:" + f1);
//            System.out.println("任务2执行结果:" + f2);
//            return f1 + f2;
//        }, executorService);
//        Integer integer = future.get();
//        System.out.println("任务3："+integer);

        /**
         * 6.两任务组合 - 一个完成
         *
         * runAfterEither:两任务有一个任务执行完成，不需要获取任务的执行结果，就能执行任务3，也没有返回值
         * public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action)
         * public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action)
         * public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor)
         *
         * acceptEither:两个任务有一个执行完成，获取它的返回值，执行任务3，没有返回值
         * public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
         * public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)
         * public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action,Executor executor)
         *
         * applyToEither:两个任务有一个执行完成，获取它的返回值，执行任务3，有返回值
         * public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
         * public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn)
         * public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor)
         *
         */
        //任务1执行完，任务2还在休眠，任务3就可以开始了
//        future1.runAfterEitherAsync(future2,()->{
//            System.out.println("任务3开始...");
//        },executorService);

//        future1.acceptEitherAsync(future2,(result)->{
//            System.out.println("任务3开始...");
//            System.out.println("之前的结果:"+result);
//        },executorService);

//        CompletableFuture<Integer> future = future1.applyToEitherAsync(future2, (result) -> {
//            System.out.println("任务3开始...");
//            System.out.println("之前的结果:" + result);
//            return result * 2;
//        }, executorService);
//        Integer integer = future.get();
//        System.out.println("任务3："+integer);


        /**
         * 7.多任务组合
         *
         *  allOf:等待所有任务完成
         *  public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
         *  anyOf:只要有一个任务完成
         *  public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
         */

        CompletableFuture<String> futrueImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        },executorService);

        CompletableFuture<String> futrueAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256G";
        },executorService);

        CompletableFuture<String> futrueDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "华为";
        },executorService);

        CompletableFuture<Void> allOf = CompletableFuture.allOf(futrueImg, futrueAttr, futrueDesc);
        //等待所有结果完成
        allOf.get();
        System.out.println("futrueImg任务的结果："+futrueImg.get());
        System.out.println("futrueAttr任务的结果："+futrueAttr.get());
        System.out.println("futrueDesc任务的结果："+futrueDesc.get());

        System.out.println("main方法...end...");
    }

}
